﻿/**************************************************************
 *
 * 唯一标识：ce04f742-b32b-42ab-b340-955cc85447d7
 * 命名空间：Sgr.Data
 * 创建时间：2024/6/18 23:15:50
 * 机器名称：DESKTOP-HJ4OAG9
 * 创建者：CocoYuan
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using Sgr.Utilities;
using System;
using System.Collections.Concurrent;
using System.Text.Json;
using System.Xml.Linq;

namespace Sgr.Data
{
    /// <summary>
    /// 默认数据库连接字符串解析器
    /// 支持主从库连接字符串的解析和从库的轮询负载均衡
    /// </summary>
    public class DefalutSlaveDataConnectionStringResolve : ISlaveDataConnectionStringResolve
    {
        /// <summary>
        /// 从库索引缓存键格式
        /// DC_S_INDEX_{数据源名称}
        /// </summary>
        private const string SLAVE_INDEX_CACHE_KEY_FORMAT = "DC_S_INDEX_{0}";

        /// <summary>
        /// 从库索引缓存字典
        /// 用于存储各个数据源的从库轮询索引
        /// </summary>
        private static readonly ConcurrentDictionary<string, int> SlaveIndexCache = new ConcurrentDictionary<string, int>();

        /// <summary>
        /// 初始化默认数据库连接字符串解析器
        /// </summary>
        public DefalutSlaveDataConnectionStringResolve()
        { }

        public virtual string GetSlaveDatabaseConnectionString(DataConnectionString dataConnectionString)
        {
            Check.NotNull(dataConnectionString, nameof(dataConnectionString));

            // 如果没有从库配置，返回主库连接字符串
            if (dataConnectionString.Slaves == null || dataConnectionString.Slaves.Count == 0)
                return dataConnectionString.ConnectionString;

            // 如果只有一个从库，直接返回
            if (dataConnectionString.Slaves.Count == 1)
                return dataConnectionString.Slaves[0];

            // 获取从库索引并返回对应连接字符串
            var index = GetSlaveIndex(dataConnectionString.Name, dataConnectionString.Slaves.Count);
            return dataConnectionString.Slaves[index];
        }

        /// <summary>
        /// 获取从库索引
        /// 使用轮询算法，确保从库负载均衡
        /// </summary>
        /// <param name="name">数据源名称</param>
        /// <param name="slaveCount">从库数量</param>
        /// <returns>当前应使用的从库索引</returns>
        protected virtual int GetSlaveIndex(string name, int slaveCount)
        {
            var cacheKey = string.Format(SLAVE_INDEX_CACHE_KEY_FORMAT, name);

            return SlaveIndexCache.AddOrUpdate(
                cacheKey,
                // 初始值为0
                _ => 0,
                // 更新值时，如果达到最大索引则重置为0，否则加1
                (_, oldValue) => (oldValue + 1) % slaveCount
            );
        }
    }
}